#include "fmemory.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>

#define BITSHIFT 16

static FILE *memory_mapped_file = NULL;
static long memnum = 0;

void *falloc(size_t size) {
  void *ptr = NULL;

  if(memory_mapped_file == NULL) {
    if((memory_mapped_file = fopen("$MEMORY", "w+")) == NULL) return NULL;
  } else if(ftell(memory_mapped_file) > 1L << BITSHIFT) { //We would overwrite...
    errno = EFAULT;
    return NULL;
  }
  ++memnum; //Get next...
  ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(memory_mapped_file), memnum << BITSHIFT);
  fwrite(&ptr, sizeof(ptr), 1, memory_mapped_file);
  fwrite(&size, sizeof(size), 1, memory_mapped_file);
  memnum += size >> BITSHIFT;
  ftruncate(fileno(memory_mapped_file), (memnum + 1) << BITSHIFT);
  if(ptr == NULL) errno = ENOMEM;
  return ptr;
}

void ffree(void *ptr) {
  long i, pos;
  void *allocated;
  size_t size;

  pos = ftell(memory_mapped_file);
  rewind(memory_mapped_file);
  for(i = 0; i < memnum; ++i) {
    fread(&allocated, sizeof(allocated), 1, memory_mapped_file);
    fread(&size, sizeof(size), 1, memory_mapped_file);
    if(allocated == ptr) {
      munmap(ptr, size); /* We do not need to check for double free as
			    "It is not an error if the indicated range
			    does not contain any mapped pages". */
      goto end;
    }
  }
  fprintf(stderr, "Unknown free at %p\n", ptr);
  abort();
 end:
  fseek(memory_mapped_file, pos, SEEK_SET);
}
